"""
Gua框架日志中间件 - 统一处理HTTP和WebSocket日志
基于Linus设计哲学：一个中间件解决所有需求
"""
import time
import uuid
import traceback
from typing import Callable, Optional
from .logger import GuaLogger, SimpleMonitor


class LoggingMiddleware:
    """统一日志中间件 - 一个中间件解决所有需求"""
    
    def __init__(self, logger: Optional[GuaLogger] = None, slow_threshold: float = 1.0):
        self.logger = logger or GuaLogger("gua")
        self.slow_threshold = slow_threshold
        self.monitor = SimpleMonitor(self.logger)
    
    def __call__(self, app: Callable) -> Callable:
        """中间件调用接口"""
        async def wrapper(scope, receive, send):
            if scope["type"] == "http":
                await self._handle_http(app, scope, receive, send)
            elif scope["type"] == "websocket":
                await self._handle_websocket(app, scope, receive, send)
            else:
                await app(scope, receive, send)
        return wrapper
    
    async def _handle_http(self, app: Callable, scope: dict, receive: Callable, send: Callable):
        """处理HTTP请求"""
        start_time = time.time()
        request_id = str(uuid.uuid4())[:8]  # 短ID，节省空间
        
        # 提取请求信息
        method = scope.get("method", "GET")
        path = scope["path"]
        headers = dict(scope.get("headers", []))
        user_agent = headers.get(b"user-agent", b"").decode()
        client_ip = self._get_client_ip(scope)
        
        # 记录请求开始
        self.logger.info(
            "request_started",
            request_id=request_id,
            method=method,
            path=path,
            client_ip=client_ip,
            user_agent=user_agent[:100] if user_agent else ""  # 限制长度
        )
        
        # 创建包装的send函数来捕获响应
        response_status = None
        response_size = 0
        
        async def wrapped_send(message):
            nonlocal response_status, response_size
            if message["type"] == "http.response.start":
                response_status = message.get("status", 200)
            elif message["type"] == "http.response.body":
                response_size += len(message.get("body", b""))
            await send(message)
        
        # 执行请求
        is_error = False
        try:
            await app(scope, receive, wrapped_send)
        except Exception as e:
            is_error = True
            # 记录错误详情
            self.logger.error(
                f"请求失败: {path}",
                event="request_failed",
                request_id=request_id,
                method=method,
                path=path,
                error=str(e),
                error_type=type(e).__name__,
                traceback=traceback.format_exc()
            )
            raise
        finally:
            # 计算请求时间
            duration = time.time() - start_time
            
            # 记录请求完成
            self.logger.info(
                "request_completed",
                request_id=request_id,
                method=method,
                path=path,
                status=response_status or 500,
                duration=duration,
                size=response_size
            )
            
            # 检查慢请求
            if duration > self.slow_threshold:
                self.logger.warn(
                    "slow_request",
                    request_id=request_id,
                    method=method,
                    path=path,
                    duration=duration,
                    threshold=self.slow_threshold
                )
            
            # 更新性能监控
            self.monitor.record_request(duration, is_error)
    
    async def _handle_websocket(self, app: Callable, scope: dict, receive: Callable, send: Callable):
        """处理WebSocket连接"""
        connection_id = str(uuid.uuid4())[:8]
        path = scope["path"]
        headers = dict(scope.get("headers", []))
        client_ip = self._get_client_ip(scope)
        
        # 记录连接建立
        self.logger.info(
            "websocket_connected",
            connection_id=connection_id,
            path=path,
            client_ip=client_ip,
            headers=headers,
        )
        
        # 创建包装的receive和send来追踪消息
        message_count = 0
        
        async def wrapped_receive():
            nonlocal message_count
            try:
                message = await receive()
                if message["type"] == "websocket.receive":
                    message_count += 1
                    self.logger.debug(
                        "websocket_message_received",
                        connection_id=connection_id,
                        message_type=message.get("type", "unknown"),
                        message_count=message_count
                    )
                return message
            except Exception as e:
                self.logger.error(
                    f"WebSocket接收错误: {connection_id}",
                    event="websocket_receive_error",
                    connection_id=connection_id,
                    error=str(e)
                )
                raise
        
        async def wrapped_send(message):
            try:
                if message["type"] in ["websocket.send", "websocket.close"]:
                    self.logger.debug(
                        "websocket_message_sent",
                        connection_id=connection_id,
                        message_type=message["type"]
                    )
                await send(message)
            except Exception as e:
                self.logger.error(
                    f"WebSocket发送错误: {connection_id}",
                    event="websocket_send_error",
                    connection_id=connection_id,
                    error=str(e)
                )
                raise
        
        # 执行WebSocket处理
        try:
            await app(scope, wrapped_receive, wrapped_send)
        except Exception as e:
            self.logger.error(
                f"WebSocket错误: {path}",
                event="websocket_error",
                connection_id=connection_id,
                path=path,
                error=str(e),
                traceback=traceback.format_exc()
            )
            raise
        finally:
            # 记录连接关闭
            self.logger.info(
                "websocket_disconnected",
                connection_id=connection_id,
                path=path,
                message_count=message_count
            )
    
    def _get_client_ip(self, scope: dict) -> str:
        """获取客户端IP地址"""
        # 尝试从headers中获取真实IP
        headers = dict(scope.get("headers", []))
        
        # 检查常见的代理头
        for header_name in [b"x-forwarded-for", b"x-real-ip", b"cf-connecting-ip"]:
            if header_name in headers:
                ip = headers[header_name].decode().split(",")[0].strip()
                if ip:
                    return ip
        
        # 从ASGI scope中获取
        client = scope.get("client")
        if client:
            return f"{client[0]}:{client[1]}"
        
        return "unknown"
    
    def get_stats(self) -> dict:
        """获取性能统计信息"""
        return self.monitor.get_stats()


# 便利函数，用于快速创建日志中间件
def logging_middleware(logger: Optional[GuaLogger] = None, slow_threshold: float = 1.0):
    """创建日志中间件的便利函数"""
    return LoggingMiddleware(logger, slow_threshold)